import {BasicMapperI} from './basicMapper.I';

interface Data {
  [prop: string]: any;
}

function getMatched<T extends Data>(item: T, value: T): boolean {
  return Object.keys(value).every((key: string) => item[key] === value[key]);
}

class BasicMapper implements BasicMapperI {
  find<T extends Data>(list: Array<T>, value: { [prop: string]: any }): Array<T> {
    return list.filter((item: T) => getMatched(item, value));
  }

  findOne<T extends Data>(list: Array<T>, value: { [prop: string]: any }): T | undefined {
    return list.find((item: T) => getMatched(item, value));
  }

  findOneById<T extends Data>(list: Array<T>, id: string): T | undefined {
    return list.find((value: T) => value.id === id);
  }

  findWhereIn<T extends Data>(list: Array<T>, arr: Array<any>, where: string): Array<T> {
    return list.filter((item: T) => arr.includes(item[where]));
  }

  insertMany<T extends Data>(list: Array<T>, arr: Array<T>): Array<T> {
    return [...list, ...arr];
  }

  remove<T extends Data>(list: Array<T>, value: any): Array<T> {
    return list.filter((item: T) => !getMatched(item, value));
  }

  removeWhereIn<T extends Data>(list: Array<T>, arr: Array<any>, where: string): Array<T> {
    return list.filter((item: T) => !arr.includes(item[where]));
  }

  updateById<T extends Data>(list: Array<T>, newData: T): Array<T> {
    return list.reduce((pre: Array<T>, oldData: T) => [
      ...pre,
      oldData.id === newData.id ? {...oldData, ...newData} : oldData
    ], []);
  }

  updateByField<T extends Data>(list: Array<T>, newData: any, field: string): Array<T> {
    return list.reduce((pre: Array<T>, oldData: T) => [
      ...pre,
      oldData[field] === newData[field] ? {...oldData, ...newData} : oldData
    ], []);
  }

  updateByIdNotIn<T extends Data>(list: Array<T>, notInList: Array<any>, newData: T): Array<T> {
    return list.reduce((pre: Array<T>, oldData: T) => [
      ...pre,
      !notInList.includes(oldData.id) ? {...oldData, ...newData} : oldData
    ], []);
  }
}

export const basicMapper = new BasicMapper();
